/***************************************************************
 *  Copyright (c) 2007 by GroupMe! Team (www.groupme.net)
 *  All rights reserved
 *
 *  This file is part of the GroupMe! Project. You can utilize
 *  software of the GroupMe! project under the terms of the 
 *  GNU Lesser General Public License as published by the
 *  Free Software Foundation in version 2.1.
 * 
 *  The GNU Lesser General Public License can be found at:
 *  http://www.gnu.org/licenses/lgpl.html
 *
 *  This copyright notice MUST APPEAR in all copies of the file!
 ***************************************************************/
package net.groupme.model.dao;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.sql.Date;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import javax.sql.DataSource;

import net.groupme.exceptions.DeleteFailedException;
import net.groupme.exceptions.IDNotFoundException;
import net.groupme.exceptions.InsertFailedException;
import net.groupme.exceptions.UpdateFailedException;
import net.groupme.gui.constants.VIEW_VOCABULARY;
import net.groupme.model.Group;
import net.groupme.model.MODEL_CONSTANTS;
import net.groupme.model.ObjectFactory;
import net.groupme.model.Tag;
import net.groupme.model.User;
import net.groupme.model.dao.rdf.StatementDAOImpl;
import net.groupme.model.rdf.Statement;
import net.groupme.utils.sql.GetGroupsQuery;
import net.groupme.utils.sql.GetStatementsQuery;
import net.groupme.utils.sql.GetStringFromTableWhereIDQuery;
import net.groupme.utils.sql.GetTagsQuery;

import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.SqlUpdate;
import org.springframework.jdbc.support.GeneratedKeyHolder;

/**
 * 
 * This class provides... This interface defines...
 * 
 * @author Mischa Frank <a
 *         href="mailto:code@planetfrank.net">code@planetfrank.net</a>
 * 
 * @version 1.0, created on 30.04.2007
 * 
 */
public class ResourceDAOImpl implements ResourceDAO {

	private static final Logger log = Logger.getLogger(ResourceDAOImpl.class);

	private DataSource ds;

	protected final String id;
	/** the type of the resource */
	private String type = null;

	private String query;

	public ResourceDAOImpl(DataSource ds, String id) {
		this.ds = ds;
		this.id = id;
	}

	public ResourceDAOImpl(DataSource ds, String name, String description, String type, URL url)
			throws InsertFailedException {
		this.ds = ds;
		SqlUpdate su = new SqlUpdate(ds, "INSERT INTO " + DATABASE_CONSTANTS.TABLE_RESOURCE//$NON-NLS-1$
				+ " (" + DATABASE_CONSTANTS.RESOURCE_NAME + ", "
				+ DATABASE_CONSTANTS.RESOURCE_DESCRIPTION + ", " + DATABASE_CONSTANTS.RESOURCE_TYPE
				+ ", " + DATABASE_CONSTANTS.RESOURCE_URL + ") VALUES (?, ?, ?, ?)");
		su.declareParameter(new SqlParameter("name", Types.VARCHAR)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("description", Types.VARCHAR)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("type", Types.VARCHAR)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("url", Types.VARCHAR)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[4];
		oa[0] = new String(name);
		oa[1] = description;
		oa[2] = new String(type);
		oa[3] = "NULL";
		if (url != null) {
			oa[3] = new String(url.toString());
		}
		GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
		int count = su.update(oa, keyHolder);
		if (count == 0)
			throw new InsertFailedException();
		this.id = keyHolder.getKey().toString();
		this.type = type;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#getId()
	 */
	public String getId() {
		return id;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.groupme.model.Resource#addStatement(net.groupme.model.rdf.Statement)
	 */
	public void addStatement(String property, String object, String datatype)
			throws IDNotFoundException, InsertFailedException {
		new StatementDAOImpl(ds, this, property, object, datatype);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#addTag(net.groupme.model.User,
	 * net.groupme.model.Tag)
	 */
	public void addTag(User tagger, Tag tag) throws InsertFailedException {
		this.addTag(tagger, tag, null, 1.00);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#addTag(net.groupme.model.User,
	 * net.groupme.model.Tag, net.groupme.model.Group)
	 */
	public void addTag(User tagger, Tag tag, Group group) throws InsertFailedException {
		this.addTag(tagger, tag, group, 1.00);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#addTag(net.groupme.model.User,
	 * net.groupme.model.Tag, net.groupme.model.Group, java.lang.Double)
	 */
	public void addTag(User tagger, Tag tag, Group group, Double importance)
			throws InsertFailedException {
		Collection<Tag> tags = this.getTags(tagger, group);
		Iterator iter = tags.iterator();
		while (iter.hasNext()) {
			Tag element = (Tag) iter.next();
			if (tag.getKeyword().equals(element.getKeyword())) {
				return;
			}
		}
		if (tag.getKeyword().contains(",") || tag.getKeyword().contains(";")) {
			StringTokenizer tokenizer = new StringTokenizer(tag.getKeyword(), ",;");
			while (tokenizer.hasMoreTokens()) {
				String newKeyword = tokenizer.nextToken().trim();
				Tag newtag = ObjectFactory.getTagForKeyword(newKeyword);
				this.addTag(tagger, newtag, group, importance);
			}
			return;
		} else {
			log.info("Adding tag: " + tag.getKeyword());
			SqlUpdate su = new SqlUpdate(ds,
					"INSERT INTO " + DATABASE_CONSTANTS.TABLE_USERTAGGROUPRESOURCE //$NON-NLS-1$
							+ " (" + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_USERID + ", "
							+ DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID + ", "
							+ DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_GROUPID + ", "
							+ DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_RESOURCEID + ", "
							+ DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_DATE + ", "
							+ DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_IMPORTANCE
							+ ") VALUES (?, ?, ?, ?, ? ,?)");
			su.declareParameter(new SqlParameter("UserID", Types.INTEGER)); //$NON-NLS-1$
			su.declareParameter(new SqlParameter("TagID", Types.INTEGER)); //$NON-NLS-1$
			su.declareParameter(new SqlParameter("GroupID", Types.INTEGER)); //$NON-NLS-1$
			su.declareParameter(new SqlParameter("ResourceID", Types.INTEGER)); //$NON-NLS-1$
			su.declareParameter(new SqlParameter("Date", Types.DATE)); //$NON-NLS-1$
			su.declareParameter(new SqlParameter("Importance", Types.DOUBLE)); //$NON-NLS-1$
			su.compile();
			Object[] oa = new Object[6];
			oa[0] = tagger.getId();
			oa[1] = tag.getId();
			if (group != null) {
				oa[2] = group.getId();
			} else {
				oa[2] = null;
			}
			oa[3] = this.id;
			oa[4] = new Date(System.currentTimeMillis());
			oa[5] = importance;
			int count = su.update(oa);
			if (count == 0) {
				throw new InsertFailedException();
			}
			// Method for informing the logging table of the Tag
			SqlUpdate su2 = new SqlUpdate(ds, "Insert Into "
					+ DATABASE_CONSTANTS.TABLE_LOG_EVENT_ACTION + " ("
					+ DATABASE_CONSTANTS.TABLE_LOG_EVENT_ACTION_USER_ID + ", "
					+ DATABASE_CONSTANTS.TABLE_LOG_EVENT_ACTION_GROUP_ID + ", "
					+ DATABASE_CONSTANTS.TABLE_LOG_EVENT_ACTION_RESOURCE_ID + ", "
					+ DATABASE_CONSTANTS.TABLE_LOG_EVENT_ACTION_TAG_ID + ", "
					+ DATABASE_CONSTANTS.TABLE_LOG_EVENT_ACTION_ACTION + ") VALUES (?, ?, ?, ?, ?)");
			su2.declareParameter(new SqlParameter("UserID", Types.INTEGER));
			su2.declareParameter(new SqlParameter("GroupID", Types.INTEGER));
			su2.declareParameter(new SqlParameter("ResourceID", Types.INTEGER));
			su2.declareParameter(new SqlParameter("TagID", Types.INTEGER));
			su2.declareParameter(new SqlParameter("Action", Types.VARCHAR));
			Object[] oa2 = new Object[5];
			oa2[0] = tagger.getId();
			if (group != null) {
				oa2[1] = group.getId();
				oa2[4] = DATABASE_CONSTANTS.TABLE_LOG_EVENT_ACTION_RESOURCE_TAGGED;
			} else {
				oa2[1] = this.id;
				oa2[4] = DATABASE_CONSTANTS.TABLE_LOG_EVENT_ACTION_GROUP_TAGGED;
			}
			oa2[2] = this.id;
			oa2[3] = tag.getId();
			int count2 = su2.update(oa2);
			if (count2 == 0) {
				throw new InsertFailedException();
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#getDescription()
	 */
	public String getDescription() {
		GetStringFromTableWhereIDQuery getDescriptionQuery = new GetStringFromTableWhereIDQuery(ds,
				DATABASE_CONSTANTS.RESOURCE_DESCRIPTION, DATABASE_CONSTANTS.TABLE_RESOURCE, id);
		Iterator iter = getDescriptionQuery.execute().iterator();
		if (iter.hasNext()) {
			return (String) iter.next();
		}
		return "";
	}

	public String getDateCreated() {
		GetStringFromTableWhereIDQuery getDateQuery = new GetStringFromTableWhereIDQuery(ds,
				DATABASE_CONSTANTS.RESOURCE_TAD, DATABASE_CONSTANTS.TABLE_RESOURCE, id);
		Iterator iter = getDateQuery.execute().iterator();
		if (iter.hasNext()) {
			return (String) iter.next();
		}
		return "";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#getLabel()
	 */
	public String getLabel() {
		return this.getName() + " " + this.getURL() + " " + this.getType();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#getName()
	 */
	public String getName() {
		GetStringFromTableWhereIDQuery getNameQuery = new GetStringFromTableWhereIDQuery(ds,
				DATABASE_CONSTANTS.RESOURCE_NAME, DATABASE_CONSTANTS.TABLE_RESOURCE, id);
		Iterator iter = getNameQuery.execute().iterator();
		if (iter.hasNext()) {
			return (String) iter.next();
		}
		return "";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#getStatements()
	 */
	@SuppressWarnings("unchecked")
	public Collection<Statement> getStatements() {
		query = "SELECT " + DATABASE_CONSTANTS.METADATA_ID + " FROM " + DATABASE_CONSTANTS.TABLE_METADATA + " WHERE " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				+ DATABASE_CONSTANTS.METADATA_RESOURCE_ID + " = " + this.id;
		GetStatementsQuery getStatementsQuery = new GetStatementsQuery(ds, query,
				DATABASE_CONSTANTS.METADATA_ID);
		Iterator iter = getStatementsQuery.execute().iterator();
		if (iter.hasNext())
			return (Collection<Statement>) iter.next();
		return new ArrayList<Statement>();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#getTags()
	 */
	@SuppressWarnings("unchecked")
	public Collection<Tag> getTags() {
		query = "SELECT DISTINCT " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID + " FROM " + DATABASE_CONSTANTS.TABLE_USERTAGGROUPRESOURCE + " WHERE " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				+ DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_RESOURCEID + " = " + id; //$NON-NLS-1$
		GetTagsQuery getTagsQuery = new GetTagsQuery(ds, query,
				DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID);
		List result = getTagsQuery.execute();
		if (result.isEmpty()) {
			return new HashSet<Tag>();
		}
		Iterator iter = result.iterator();
		if (iter.hasNext()) {
			return (Collection<Tag>) iter.next();
		}
		return new ArrayList<Tag>();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#getTags(net.groupme.model.Group)
	 */
	@SuppressWarnings("unchecked")
	public Collection<Tag> getTags(Group group) {
		query = "SELECT DISTINCT " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID + " FROM " + DATABASE_CONSTANTS.TABLE_USERTAGGROUPRESOURCE + " WHERE " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				+ DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_RESOURCEID
				+ " = " + id + " AND " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_GROUPID + " = " + group.getId(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

		GetTagsQuery getTagsQuery = new GetTagsQuery(ds, query,
				DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID);

		Iterator iter = getTagsQuery.execute().iterator();
		if (iter.hasNext())
			return (Collection<Tag>) iter.next();
		return new ArrayList<Tag>();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#getTags(net.groupme.model.User)
	 */
	@SuppressWarnings("unchecked")
	public Collection<Tag> getTags(User tagger) {
		query = "SELECT DISTINCT " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID + " FROM " + DATABASE_CONSTANTS.TABLE_USERTAGGROUPRESOURCE + " WHERE " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				+ DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_RESOURCEID
				+ " = " + id + " AND " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_USERID + " = " + tagger.getId(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		GetTagsQuery getTagsQuery = new GetTagsQuery(ds, query,
				DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID);

		Iterator iter = getTagsQuery.execute().iterator();
		if (iter.hasNext())
			return (Collection<Tag>) iter.next();
		return new ArrayList<Tag>();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#getTags(net.groupme.model.User,
	 * net.groupme.model.Group)
	 */
	@SuppressWarnings("unchecked")
	public Collection<Tag> getTags(User tagger, Group group) {
		query = "SELECT DISTINCT " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID + " FROM " + DATABASE_CONSTANTS.TABLE_USERTAGGROUPRESOURCE + " WHERE " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				+ DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_RESOURCEID
				+ " = " + id + " AND " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_USERID + " = " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				+ tagger.getId() + " AND ";
		if (group != null) {
			// tags for resource in context of a group:
			query += DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_GROUPID + " = " + group.getId(); //$NON-NLS-1$ 
		} else {
			// tags for groups without being within another group:
			query += DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_GROUPID + " is NULL"; //$NON-NLS-1$ 
		}

		GetTagsQuery getTagsQuery = new GetTagsQuery(ds, query,
				DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID);
		Iterator iter = getTagsQuery.execute().iterator();
		if (iter.hasNext()) {
			return (Collection<Tag>) iter.next();
		}
		return new ArrayList<Tag>();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#getType()
	 */
	public String getType() {
		if (this.type == null) {
			GetStringFromTableWhereIDQuery getTypeQuery = new GetStringFromTableWhereIDQuery(ds,
					DATABASE_CONSTANTS.RESOURCE_TYPE, DATABASE_CONSTANTS.TABLE_RESOURCE, id);
			Iterator iter = getTypeQuery.execute().iterator();
			if (iter.hasNext()) {
				this.type = (String) iter.next();
			}
		}
		return this.type;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#getURI()
	 */
	public URI getURI() {
		try {
			if (MODEL_CONSTANTS.RESOURCE_TYPE_GROUP.equals(this.getType())) {
				return new URI(VIEW_VOCABULARY.RESTful_GROUP_URI_PATTERN + id);
			}
			return new URI(VIEW_VOCABULARY.RESTful_RESOURCE_URI_PATTERN + id);//$NON-NLS-1$
		} catch (URISyntaxException e) {
			e.printStackTrace();
			return null;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#getURL()
	 */
	public URL getURL() {
		GetStringFromTableWhereIDQuery getURLQuery = new GetStringFromTableWhereIDQuery(ds,
				DATABASE_CONSTANTS.RESOURCE_URL, DATABASE_CONSTANTS.TABLE_RESOURCE, id);
		try {
			URL url = new URL((String) getURLQuery.execute().iterator().next());
			return url;
		} catch (DataAccessException e) {
			log.debug(e.getMessage());
		} catch (MalformedURLException e) {
			log.debug(e.getMessage());
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.groupme.model.Resource#removeStatement(net.groupme.model.rdf.Statement
	 * )
	 */
	public void removeStatement(Statement statement) throws DeleteFailedException {
		SqlUpdate su;
		su = new SqlUpdate(ds, "DELETE FROM " + DATABASE_CONSTANTS.TABLE_METADATA + " WHERE "
				+ DATABASE_CONSTANTS.METADATA_ID + " = " + statement.getId());
		su.compile();
		int count = su.update();
		if (count == 0)
			throw new DeleteFailedException();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#removeTag(net.groupme.model.User,
	 * net.groupme.model.Tag, net.groupme.model.Group)
	 */
	public void removeTag(User tagger, Tag tag, Group group) throws DeleteFailedException {
		SqlUpdate su;
		su = new SqlUpdate(
				ds,
				"DELETE FROM " + DATABASE_CONSTANTS.TABLE_USERTAGGROUPRESOURCE //$NON-NLS-1$
						+ " WHERE " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_USERID + " = " + tagger.getId() //$NON-NLS-1$ //$NON-NLS-2$
						+ " AND " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_TAGID + " = " + tag.getId() //$NON-NLS-1$ //$NON-NLS-2$
						+ " AND " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_GROUPID + " = " + group.getId() //$NON-NLS-1$ //$NON-NLS-2$
						+ " AND " + DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_RESOURCEID + " = " + this.id); //$NON-NLS-1$ //$NON-NLS-2$
		su.compile();
		int count = su.update();
		if (count == 0)
			throw new DeleteFailedException();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#setDescription(java.lang.String)
	 */
	public void setDescription(String description) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + DATABASE_CONSTANTS.TABLE_RESOURCE + " SET " + DATABASE_CONSTANTS.RESOURCE_DESCRIPTION + " = ? WHERE " + DATABASE_CONSTANTS.RESOURCE_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("description", Types.VARCHAR)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = description;
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Identifiable#setLabel(java.lang.String)
	 */
	public void setLabel(String label) {
		// no need to be implemented

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#setName(java.lang.String)
	 */
	public void setName(String name) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + DATABASE_CONSTANTS.TABLE_RESOURCE + " SET " + DATABASE_CONSTANTS.RESOURCE_NAME + " = ? WHERE " + DATABASE_CONSTANTS.RESOURCE_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("name", Types.VARCHAR)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = name;
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#setType(java.lang.String)
	 */
	public void setType(String type) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + DATABASE_CONSTANTS.TABLE_RESOURCE + " SET " + DATABASE_CONSTANTS.RESOURCE_TYPE + " = ? WHERE " + DATABASE_CONSTANTS.RESOURCE_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("type", Types.VARCHAR)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = type;
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#setURL(java.net.URL)
	 */
	public void setURL(URL url) throws UpdateFailedException {
		SqlUpdate su = new SqlUpdate(
				ds,
				"UPDATE " + DATABASE_CONSTANTS.TABLE_RESOURCE + " SET " + DATABASE_CONSTANTS.RESOURCE_URL + " = ? WHERE " + DATABASE_CONSTANTS.RESOURCE_ID + " = ?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
		su.declareParameter(new SqlParameter("url", Types.VARCHAR)); //$NON-NLS-1$
		su.declareParameter(new SqlParameter("ID", Types.INTEGER)); //$NON-NLS-1$
		su.compile();
		Object[] oa = new Object[2];
		oa[0] = url.toString();
		oa[1] = new Integer(id);
		int count = su.update(oa);
		if (count == 0)
			throw new UpdateFailedException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.groupme.model.Resource#getGroups()
	 */
	@SuppressWarnings("unchecked")
	public Collection<Group> getGroups() {
		query = "SELECT DISTINCT " + DATABASE_CONSTANTS.GROUPRESOURCE_GROUP_ID + " FROM " + DATABASE_CONSTANTS.TABLE_GROUPRESOURCE + " as g, " + DATABASE_CONSTANTS.TABLE_RESOURCE + " as r WHERE " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				+ " g." + DATABASE_CONSTANTS.GROUPRESOURCE_RESOURCE_ID + " = " + id + " AND g."
				+ DATABASE_CONSTANTS.GROUPRESOURCE_GROUP_ID + " = r."
				+ DATABASE_CONSTANTS.RESOURCE_ID + " AND r." + DATABASE_CONSTANTS.RESOURCE_TYPE
				+ " != '" + MODEL_CONSTANTS.RESOURCE_TYPE_QUEUE + "'";
		GetGroupsQuery getTagsQuery = new GetGroupsQuery(ds, query,
				DATABASE_CONSTANTS.USERTAGGROUPRESOURCE_GROUPID);
		Iterator iter = getTagsQuery.execute().iterator();
		if (iter.hasNext()) {
			return (Collection<Group>) iter.next();
		}
		return new ArrayList<Group>();
	}
}
